package com.sk.bilibili.utils;

import com.sk.bilibili.dto.SlideCode;
import com.sk.bilibili.property.SlideCodeProperty;
import lombok.SneakyThrows;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.stereotype.Component;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

/**
 * @author 邵康
 * @date 2021/11/22 12:36
 */
@Component
public class SlideCodeUtils implements InitializingBean {

    @Autowired
    private SlideCodeProperty slideCodeProperty;
    @Autowired
    private ResourcePatternResolver resolver;

    public SlideCode generateSlideCode(){
        BufferedImage bg=getRandomImage(bgs);
        BufferedImage slider=getRandomImage(sliders);
        int[][] pos=getPos();//获取随机位置  第一个为正确位置
        bg=handleBg(bg,slider,pos);
        slider=handleSlider(slider,pos[0][1]);
        SlideCode slideCode = new SlideCode();
        slideCode.setOffset(pos[0][0]);
        slideCode.setSlide(encode(slider));
        slideCode.setBackground(encode(bg));
        return slideCode;
    }

    @SneakyThrows
    private String encode(BufferedImage image) {
        ByteArrayOutputStream os=new ByteArrayOutputStream();
        ImageIO.write(image,"png",os);
        return Base64Utils.encode(os);
    }

    private BufferedImage handleSlider(BufferedImage slider, int y) {
        BufferedImage res=new BufferedImage(slideCodeProperty.getSliderWidth(),
                slideCodeProperty.getBgHeight(),BufferedImage.TYPE_4BYTE_ABGR);
        res.getGraphics().drawImage(slider,0,y,null);
        return res;
    }

    private BufferedImage handleBg(BufferedImage bg, BufferedImage slider, int[][] pos) {
        int bgH = bg.getHeight();
        int bgW = bg.getWidth();
        int[] bgColor = new int[bgH * bgW];
        bg.getRGB(0, 0, bgW, bgH, bgColor, 0, bgW);
        int sliderH=slider.getHeight();
        int sliderW=slider.getWidth();
        int[] sliderColor=new int[sliderH*sliderW];
        slider.getRGB(0,0,sliderW,sliderH,sliderColor,0,sliderW);
        int index;
        int[] srcColor = new int[4];
        int threshold = slideCodeProperty.getThreshold();
        int darkCount = slideCodeProperty.getDarkCount();
        for (int i = 0; i < sliderH; i++) {
            for (int j = 0; j < sliderW; j++) {
                index = i * sliderW + j;
                if(((sliderColor[index] >> 24) & 0xff)>threshold){
                    for (int[] po : pos) {
                        index=(i+po[1])*bgW+j+po[0];
                        srcColor[0] = (bgColor[index] >> 24) & 0xff;   //  a
                        srcColor[1] = Math.max(((bgColor[index] >> 16) & 0xff)-darkCount,0); // r
                        srcColor[2] = Math.max(((bgColor[index] >> 8) & 0xff)-darkCount,0); // g
                        srcColor[3] = Math.max((bgColor[index] & 0xff)-darkCount,0);   //  b
                        bgColor[index] = (srcColor[0] << 24) | (srcColor[1] << 16) |
                                (srcColor[2] << 8) | srcColor[3];
                    }
                }
            }
        }
        BufferedImage image = new BufferedImage(bgW, bgH, BufferedImage.TYPE_4BYTE_ABGR);
        image.setRGB(0,0,bgW,bgH,bgColor,0,bgW);
        return image;
    }

    private int[][] getPos() {
        int[][] pos=new int[slideCodeProperty.getInterferenceNum()+1][2];
        int w=slideCodeProperty.getBgWidth()-slideCodeProperty.getSliderWidth();
        int h=slideCodeProperty.getBgHeight()-slideCodeProperty.getSliderHeight();
        for (int i = 0; i < pos.length; i++) {
            pos[i][0]=random.nextInt(w);
            pos[i][1]=random.nextInt(h);
        }
        return pos;
    }

    private BufferedImage getRandomImage(List<BufferedImage> images) {
        return images.get(random.nextInt(images.size()));
    }

    private List<BufferedImage> bgs;
    private List<BufferedImage> sliders;
    private Random random;

    @Override
    public void afterPropertiesSet() throws Exception {
        bgs=loadImage(slideCodeProperty.getBgPath(),slideCodeProperty.getBgWidth(),
                slideCodeProperty.getBgHeight());
        sliders=loadImage(slideCodeProperty.getSliderPath(),slideCodeProperty.getSliderWidth(),
                slideCodeProperty.getSliderHeight());
        random=new Random();
    }

    @SneakyThrows
    private List<BufferedImage> loadImage(String path, int width, int height) {
        Resource[] resources = resolver.getResources(path);
        List<BufferedImage> res=new ArrayList<>();
        for (Resource resource:resources){
            res.add(doLoadImage(resource,width,height));
        }
        return res;
    }

    @SneakyThrows
    private BufferedImage doLoadImage(Resource resource, int width, int height) {
        BufferedImage image = ImageIO.read(resource.getInputStream());
        int w = image.getWidth();
        int h = image.getHeight();
        if(w==width&&h==height)return image;
        BufferedImage res = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
        res.getGraphics().drawImage(image,0,0,width,height,null);
        return res;
    }

}
